package com.suma.boot.redis;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * redis配置类
 *
 * @author suma
 * @date 2018/1/18 下午1:39
 */
@EnableCaching
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfiguration extends CachingConfigurerSupport {

	@Autowired
	private RedisProperties redisProperties;

	/**
	 * 连接redis的工厂类
	 *
	 * @return
	 */
	@Bean
	public JedisConnectionFactory jedisConnectionFactory() {
		JedisConnectionFactory factory = new JedisConnectionFactory();
		factory.setHostName(redisProperties.getHost());
		factory.setPort(redisProperties.getPort());
		factory.setTimeout(redisProperties.getTimeout());
		factory.setPassword(redisProperties.getPassword());
		factory.setDatabase(redisProperties.getDatabase());
		factory.afterPropertiesSet();
		return factory;
	}

	/**
	 * 配置RedisTemplate 设置添加序列化器 key 使用string序列化器 value 使用Json序列化器
	 * 还有一种简答的设置方式，改变defaultSerializer对象的实现。
	 *
	 * @return
	 */
	@Bean
	public RedisTemplate<String, Object> redisTemplate() {
		// StringRedisTemplate的构造方法中默认设置了stringSerializer
		RedisTemplate<String, Object> template = new RedisTemplate<>();
		// set key serializer
		StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
		template.setKeySerializer(stringRedisSerializer);
		template.setHashKeySerializer(stringRedisSerializer);

		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
		ObjectMapper objectMapper = new ObjectMapper();
		objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

		jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
		// set value serializer
		template.setDefaultSerializer(jackson2JsonRedisSerializer);

		template.setConnectionFactory(jedisConnectionFactory());
		template.afterPropertiesSet();
		return template;
	}

	/**
	 * 设置RedisCacheManager 使用cache注解管理redis缓存
	 *
	 * @return
	 */
	@Bean
	@Override
	public RedisCacheManager cacheManager() {
		RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate());
		Map<String, Long> expires = new HashMap<>();
		redisCacheManager.setExpires(expires);
		return redisCacheManager;
	}

	/**
	 * 自定义生成redis-key
	 *
	 * @return
	 */
	@Override
	public KeyGenerator keyGenerator() {
		return new KeyGenerator() {
			@Override
			public Object generate(Object o, Method method, Object... objects) {
				StringBuilder sb = new StringBuilder();
				sb.append(o.getClass().getName()).append(".");
				sb.append(method.getName()).append(".");
				for (Object obj : objects) {
					if (obj != null) {
						sb.append(obj.toString());
					}
				}
				return sb.toString();
			}
		};
	}
}
